#!/bin/env python
# -*- coding: utf-8 -*-

#This file is part of pyLot library.
#
# pyLot is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# pyLot is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with pyLot.  If not, see <http://www.gnu.org/licenses/>.

__author__ = u'Pierre Puiseux, Guillaume Baty'
__copyright__ = u"Copyright 2011-2012 (C) andheo, Université de Pau et des Pays de l'Adour"
__credits__ = [u'Pierre Puiseux', u'Guillaume Baty']
__license__ = "GNU Lesser General Public License"

__all__ = [u'PathBook']

from _pylot.minimal.container import Container
from _pylot.minimal.datum import Datum
from _pylot.minimal.path import Path
from _pylot.minimal.system import ENCODING
from _pylot.minimal.utils import check_type, error, Utils
from _pylot.data import regexpr

class PathBook (Container) :
  u"""
  Special Container designed for Path

  Takes two extra parameters
    - expanduser : if True [default] convert ~ to /home/user
    - abspath : if True [default] always return absolute paths

  Example :

  >>> from pyLot.core import Datum, Path
  >>> b = PathBook(data=[Datum(u'abs', Path, u'/tmp/dir')])
  >>> b[u'abs']
  Datum(u'abs', Path, Path(u'/tmp/dir'), None, [Path(u'/tmp/dir')], None, None, None)

  >>> print b.nature
  <class '_pylot.minimal.path.Path'>
  >>> b(u'abs')
  Path(u'/tmp/dir')
  
  >>> import os
  >>> b[u'home'] = u'~/test'
  >>> b(u'home') == os.path.expanduser(u'~/test')
  True
  
  >>> b[u'INT']=12
  Traceback (most recent call last):
     ...
  TypeError: E006 - Path, unicode expected, got int
  >>> u'INT' in b
  False
  
  """

  valid_file_format = (u'csv', u'pylot')
  best_file_format = u'csv'

  def __init__ (self, *args, **kargs):

    # TODO: Python3: remove lines from here ...
    new_dict = {}
    for key, value in kargs.items() :
      new_dict[key.encode(ENCODING)] = value
    # ... to here

    if u'identity' in kargs :
      identity = new_dict.pop(u'identity')
      new_dict.update(dict(
        name=identity.name,
        alias=identity.alias,
        nature=identity.nature))

    super(PathBook, self).__init__(*args, **new_dict)
    self.nature = Path

    self.expanduser = True
    self.abspath = True

#  def __setitem__(self, key, value):
#    if isinstance(value, Path):
#      value = Datum(unicode(key), value=value)
#    elif isinstance(value, unicode):
#      value = Datum(unicode(key), Path, value)
#    elif isinstance(value, Datum) :
#      pass
#    else :
#      check_type(u'value', value, [Datum, Path, unicode])
#    super(PathBook, self).__setitem__(key, value)

  def convert(self, val, nat):
    return self.nature(val).expanduser()

  def upFromFile (self, src, dataformat=None, entries=None, mod_attrs=None,
                  only_existing_keys=False) :
    u"""
    Updates book from a file.
    File format is detected from filename extension
    Supported file formats are defined in Book.valid_file_format

    :param dataformat: force file format
    :type dataformat: unicode

    :param src: file path
    :type src: unicode or Path
    """
    # TODO: support only_existing_keys
    check_type(u'src', src, (unicode, Path))
    check_type(u'dataformat', dataformat, unicode, none=True)
    check_type(u'entries', entries, [list, tuple], none=True)
    check_type(u'mod_attrs', mod_attrs, [list, tuple], none=True)

    src = Path(src)
    if dataformat is None :
      if src.ext == u'.csv' :
        dataformat = u'csv'
      elif src.ext == u'.pylot' :
        dataformat = u'pylot'
      else :
        raise ValueError, error(u'Unknown file type %s' % src)
    else :
      dataformat = dataformat.lower()

    assert(dataformat in self.valid_file_format)
    try :
      stream = Utils.readfile(src)
    except (OSError, IOError) :
      pass
    else :
      if dataformat == u'csv' :
        for line in stream :
          line = line.strip()
          if line and not regexpr.co_comment.match(line) :
            datum = self._datum_type.FromCsv(line)
            if entries is None or datum.name in entries :
              if datum :
                self.upgrade({datum.name:datum}, mod_attrs=mod_attrs)

      elif dataformat == u'pylot' :
        for line in stream :
          line = line.strip()
          if line and not regexpr.co_comment.match(line) :
            datum = self._datum_type()
            datum.upFromPyLot(line)
            if entries is None or datum.name in entries :
              if datum :
                self._up(datum, mod_attrs=mod_attrs)

      stream.close()
  def __call__ (self, pathid, *args) :
    u"""
    Returns absolute path

    :param pathid: path identifier (:attr:`Datum.name<pylot.core.Datum.name>`)
    :type pathid: str

    :return: absolute path (:class:`~pylot.core.Path`)
    """
    root = self.getDatum(pathid).value
    if root is None :
      return None
    else :
      if args :
        path = Path(root, *args)
      else :
        path = root

      if self.expanduser :
        path = path.expanduser()
      if self.abspath :
        path = path.abspath()

      return path

if __name__ == u'__main__' :

  import doctest
  doctest.testmod()

